/*
 * @Author: dingding
 * @Date: 2020-03-22 20:29:09
 * @LastEditors: ding-cx
 * @LastEditTime: 2021-02-27 11:47:44
 * @Description: 对象合并，将一个对象合并进另一个对象
 */

import objectDeepClone from "./objectDeepClone.js"

function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}





/**
 * @example: 
 * @description: 对象合并方法，将一个对象合并进另一个对象
 * @param {object} [obj] [要合并的对象]
 * @param {object} [targetObj] [目标对象，以它为基础，接受obj的属性合并进来]
 * @param {boolean} [isAdd] [当target没有这个属性时，是否添加]
 * @param {boolean} [isClone] [是否返回一个全新对象。默认返回的还是target引用]
 * @param {boolean} [isReplace] [可选的合并策略，合并时是否替换target的同属性，结合isAdd可实现只往target添加新属性而不覆盖同属性]
 * @param {boolean} [isMergeNotType] [深度递归时，如果类型不一致，是否赋值覆盖]
 * @return: {type} --- example: 
 */

export default function objectMerge(obj, targetObj, isAdd = false, isClone = false, isReplace = true, isMergeNotType = false) {
  if ((isObject(obj) && isObject(targetObj)) || (Array.isArray(obj) && Array.isArray(targetObj))) {} else {
    if (isMergeNotType) {
      targetObj = obj;
    }
    // console.error('参数obj和target必须同为对象或数组。');
    return targetObj;
  }

  obj = objectDeepClone(obj);
  if (isClone) {
    targetObj = objectDeepClone(targetObj);
  }


  /* 如果obj是对象 */
  if (isObject(obj)) {
    for (const key in obj) {
      /* 如果目标对象存在该属性 */
      if (targetObj.hasOwnProperty(key)) {
        /* 当双方都是对象时才会继续递归，否则将整个被替换 */
        if (isObject(targetObj[key]) && isObject(obj[key])) {
          targetObj[key] = objectMerge(obj[key], targetObj[key], isAdd, isClone, isReplace, isMergeNotType);
          /* 如果双方都是数组 */
        } else if (Array.isArray(targetObj[key]) && Array.isArray(obj[key])) {
          targetObj[key] = objectMerge(obj[key], targetObj[key], isAdd, isClone, isReplace, isMergeNotType)
          /* 如果obj某属性是函数，将替换target为函数 */
        } else if (typeof obj[key] === 'function') {
          targetObj[key] = obj[key].bind(targetObj)
        } else {
          if (isReplace) {
            targetObj[key] = obj[key]
          }
        }
      } else if (isAdd) {
        targetObj[key] = obj[key]
      }
    }
  } else if (Array.isArray(obj)) {
    obj.forEach((item, index) => {
      targetObj[index] = objectMerge(item, targetObj[index], isAdd, isClone, isReplace, isMergeNotType)
    })
  }

  return targetObj;
}
